<?php

namespace Sharks\Core\Persistence;

use ArrayAccess;
use Sharks\Core\Support\Base\Precondition;

/**
 * 查询时返回的对象，表示数据库中一行数据，且属性值只读；
 * 可以使用类对象访问符访问<code>-></code>,也可以使用关联数组访问符
 * 示例：
 * <pre>
 * $records = Query::createRawSelect('select * from SysUser')->lists();
 * foreach ($records as $record) {
 *     echo $record->id;
 *     echo $record->name;
 *     // or
 *     echo $record['id'];
 *     echo $record['name'];
 * }
 * </pre>
 */
class DbRecord implements ArrayAccess {

    /**
     * 转换单行数组为DbRecord对象
     * @param  array  $row 单行数组
     * @return DbRecord
     */
    public static function convert(array $row) {
        return new static($row);
    }

    /**
     * 转换多行数组为DbRecord集合对象
     * @param  array  $all 多行数组
     * @return array(DbRecord)    
     */
    public static function convertMany(array $all) {
        $result = array();
        foreach ($all as $row) {
            $result[] = new static($row);
        }
        return $result;
    }

    private $attributes;

    public function __construct(array $record) {
        $this->attributes = $record;
    }

    /**
     * 对象访问符按名称访问
     * @param  string $name 名称
     * @throws  IllegalArgumentException 不存在$name名称指向的数据时，抛出异常
     * @return mixed 数据
     */
    public function __get($name) {
        return $this->get($name);
    }

    public function attributes() {
        return $this->attributes;
    }

    /**
     * 字符串化
     * @see  DbRecord::toJson
     * @return string [description]
     */
    public function __toString() {
        return $this->toJson();
    }

    /**
     * 转化为JSON字符串。数据为空时返回"{}"
     * @see  php的json_encode方法
     * @return string json化字符串
     */
    public function toJson() {
        if (empty($this->attributes)) {
            return '{}';
        }
        return json_encode($this->attributes);
    }

    /**
     * 依据名称获取数据
     * @param  string $name 名称索引
     * @return mixed        数据
     */
    protected function get($name) {
        Precondition::check(isset($this->attributes[$name]), "$name 该属性不存在");
        return $this->attributes[$name];
    }

    public function offsetExists($offset) {
        return isset($this->attributes[$offset]);
    }

    public function offsetGet($offset) {
        return $this->get($offset);
    }

    public function offsetSet ($offset, $value ) {
        $this->attributes[$offset] = $value;
    }

    public function offsetUnset ($offset ) {
        unset($this->attributes[$offset]);
    }
}